library(ggplot2)
library(sf)
Linking to GEOS 3.10.2, GDAL 3.4.1, PROJ 8.2.1; sf_use_s2() is TRUE
library(dplyr)
Attaching package: ‘dplyr’
The following objects are masked from ‘package:stats’:
filter, lag
The following objects are masked from ‘package:base’:
intersect, setdiff, setequal, union
library(spatialreg)
Loading required package: spData
To access larger datasets in this package, install the spDataLarge package with: `install.packages('spDataLarge',
repos='https://nowosad.github.io/drat/', type='source')`
Loading required package: Matrix
library(spdep)
Attaching package: ‘spdep’
The following objects are masked from ‘package:spatialreg’:
get.ClusterOption, get.coresOption, get.mcOption, get.VerboseOption, get.ZeroPolicyOption, set.ClusterOption, set.coresOption,
set.mcOption, set.VerboseOption, set.ZeroPolicyOption
rm(list=ls())
mypath <- "./DataBackups/"
profession_names <- c(
"sales professions",
"mechatronics, energy, and electrical professions",
"professions in business management and organization",
"medical health professions",
"machine and vehicle technology professions",
"all professions"
)
kreise <- sf::st_read("./DataPreparation/Shapes/Kreise/vg1000_12-31.utm32s.shape.ebenen/vg1000_ebenen_1231/VG1000_KRS.shp") # though not imported directly, all other auxiliary files must be present in the path
Reading layer `VG1000_KRS' from data source
`/home/dennis/Desktop/Spatial Regression Analysis_cleaned/DataPreparation/Shapes/Kreise/vg1000_12-31.utm32s.shape.ebenen/vg1000_ebenen_1231/VG1000_KRS.shp'
using driver `ESRI Shapefile'
Simple feature collection with 424 features and 25 fields
Geometry type: MULTIPOLYGON
Dimension: XY
Bounding box: xmin: 280353.1 ymin: 5235878 xmax: 921261.6 ymax: 6101482
Projected CRS: ETRS89 / UTM zone 32N
kreise <- st_transform(kreise, "WGS84")
kreise_merged <- kreise %>%
group_by(SN_L) %>%
summarize(geometry = st_union(geometry))
library(stringr)
library(ggrepel)
model_list <- list()
graphics_list <- list()
spatial_clustering_list <- list()
load(file = "./DataBackups/weights_data.RData")
for (p in profession_names)
{
#p <- profession_names[1]
load(paste0(mypath,p,"M.Rdata"))
load(file = "./DataBackups/weights_data.RData")
print(p)
target = "M"
formula_base <- as.formula(paste0(target," ~ U + V "))
formula <- as.formula(paste0(target," ~ U + V + unemp25 + cons + highSE + medSE "))
formula_pub_num <- as.formula(paste0(target," ~ U + V + unemp25 + cons + highSE + medSE + Agglomeration"))
target = "M"
profession_new$Agglomeration <- profession_new$AgglomerationPublicPop49
# Begin Weight Matrix computation
columns_of_interest <- c('M','U', 'V', 'unemp25', 'cons', 'lowSE', 'medSE', 'Agglomeration')
# Replace Inf and -Inf with NA in the specified columns
profession_new[columns_of_interest] <- lapply(profession_new[columns_of_interest], function(x) replace(x, is.infinite(x), NA))
# Remove rows with any NA values in the specified columns
profession_new <- profession_new[complete.cases(profession_new[columns_of_interest]), ]
best_Weights_public_pop <- best_Weights_public_pop_mat[colnames(best_Weights_public_pop_mat) %in% profession_new$region,colnames(best_Weights_public_pop_mat) %in% profession_new$region]
################
library(dplyr)
distances_relevant_pop <- merge(distances_relevant,final, by.x="city...1",by.y="city")
distances_relevant_pop <- merge(distances_relevant_pop,final,by.x="city...4",by.y="city")
profession_new <- profession_new[!is.na(profession_new$OpenPositions),]
## As all Professions have different Regions, we need to Reduce the matrix to relevant regions. As the initial matrix, already does not contain all regions, it is easier to re-calculate evrything.
distances_relevant_test_public <- distances_relevant_pop %>% group_by(ABDistrict...6) %>% mutate(district_pop = sum(unique(maxPopulation.y))) %>% ungroup %>% filter(ABDistrict...3 != ABDistrict...6) %>% filter(public <= 51.28167) %>% group_by(city...1, ABDistrict...3, ABDistrict...6) %>% summarise(district_pop = max(district_pop), count= sum(unique(maxPopulation.y)), Weight=count/district_pop, .groups="keep") %>% group_by(ABDistrict...3, ABDistrict...6) %>% summarise(Weight=mean(Weight), .groups="keep")
Weights_public_pop <- matrix(0, nrow=nrow(profession_new), ncol=nrow(profession_new))
row.names(Weights_public_pop)<- profession_new$region
colnames(Weights_public_pop) <- profession_new$region
for(i in 1:nrow(distances_relevant_test_public))
{
Weights_public_pop[row.names(Weights_public_pop)==distances_relevant_test_public$ABDistrict...3[i], colnames(Weights_public_pop)==distances_relevant_test_public$ABDistrict...6[i]]<- distances_relevant_test_public$Weight[i]
}
Weights_public_pop <- Weights_public_pop/max(Weights_public_pop)
model <- lmSLX(formula_pub_num , profession_new, mat2listw(Weights_public_pop, style="M"), na.action=na.omit, zero.policy=TRUE, Durbin=~ U + V -1)
model_list$x <- model
names(model_list)<-c(names(model_list)[1:(length(names(model_list)))-1], p)
#
estimate_vector<- model$coefficients[-c(2,3,9:10)]
estimate_values <- as.matrix(cbind("(Intercept)"=1,st_drop_geometry(profession_new[,names(estimate_vector[-c(1)])])))
profession_new$Efficiency <- exp(estimate_values %*% estimate_vector)
map_efficiency <- ggplot() +
geom_sf(data=districts, fill = "#e4e4e4") +
geom_sf(data=st_as_sf(profession_new), aes(fill = Efficiency))+
geom_sf(data=kreise_merged,fill=NA,
color = "#ec7063",
lwd = 1.2) +
theme(legend.text.align = 1) +
labs(fill = str_wrap(paste0("Efficiency for ", p), width = 50)) +
guides(
fill = guide_colorbar(direction = "horizontal", title.hjust=0.5, title.position="top", barwidth = 20, # Adjust this value to change the width of the colorbar
barheight = 1 ),
# Adjust rows for the fill legend
) +
theme(
legend.position = "bottom",
legend.text = element_text(size = 18),
legend.title = element_text(size = 18, face="bold"),
legend.box = "horizontal",
legend.box.just = "center",
legend.spacing.x = unit(0.5, "cm")
)
map_efficiency <- map_efficiency + scale_fill_gradientn(colors = custom_colors(100), na.value="#e4e4e4")
print(map_efficiency)
graphics_list$x <- map_efficiency
names(graphics_list)<-names(model_list)
}
[1] "sales professions"
Warning: style is M (missing); style should be set to a valid valueWarning: missing spatial weights styleWarning: The `legend.text.align` argument of `theme()` is deprecated as of ggplot2 3.5.0.
Please use theme(legend.text = element_text(hjust)) instead.
[1] "mechatronics, energy, and electrical professions"
[1] "professions in business management and organization"
[1] "medical health professions"
[1] "machine and vehicle technology professions"
[1] "all professions"






library(gridExtra)
Attaching package: ‘gridExtra’
The following object is masked from ‘package:dplyr’:
combine
combined_plot <- do.call(grid.arrange, c(graphics_list, ncol = 2, nrow = 3))

print(combined_plot)
TableGrob (3 x 2) "arrange": 6 grobs
#combined_plot <- do.call(grid.arrange, c(spatial_clustering_list, ncol = 2, nrow = 3))
#print(combined_plot)
library(jtools)
library(huxtable)
Attaching package: ‘huxtable’
The following object is masked from ‘package:dplyr’:
add_rownames
The following object is masked from ‘package:ggplot2’:
theme_grey
# Combine model summaries into a single huxtable
ht <- export_summs(model_list$`all professions`,
model_list$`machine and vehicle technology professions`,
model_list$`mechatronics, energy, and electrical professions`,
model_list$`medical health professions`,
model_list$`professions in business management and organization`,
model_list$`sales professions`,
model.names = c("All Professions",
"Machine & Vehicle Technology",
"Mechatronics, Energy, Electrical",
"Medical Health",
"Business Management",
"Sales"),
number_format = "%.3f",
statistics = c("logLik","AIC","BIC","N. obs." = "nobs"),
stars = c(`***` = 0.001, `**` = 0.01, `*` = 0.05, `^` = 0.1))
Warning: The `tidy()` method for objects of class `SlX` is not maintained by the broom team, and is only supported through the `lm` tidier method. Please be cautious in interpreting and reporting broom output.
# Apply any additional formatting to the huxtable if needed
ht <- ht %>%
set_header_rows(1, TRUE) %>%
set_header_cols(1, TRUE)
# Display the huxtable
print_screen(ht)
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
All Professions Machine & Vehicle Mechatronics, Medical Health Business Management Sales
Technology Energy, Electrical
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
(Intercept) -0.509 * -0.324 -0.482 * -0.916 ** -0.551 * -0.944 **
(0.207) (0.218) (0.196) (0.338) (0.225) (0.313)
U 0.681 *** 0.508 *** 0.694 *** 0.566 *** 0.500 *** 0.691 ***
(0.039) (0.041) (0.038) (0.052) (0.046) (0.034)
V 0.316 *** 0.503 *** 0.320 *** 0.446 *** 0.519 *** 0.319 ***
(0.039) (0.042) (0.038) (0.050) (0.045) (0.033)
unemp25 -0.014 -0.006 -0.021 * 0.017 -0.008 0.005
(0.008) (0.009) (0.008) (0.016) (0.010) (0.013)
cons 0.051 * 0.002 0.065 * 0.127 ** 0.028 0.034
(0.025) (0.027) (0.025) (0.042) (0.029) (0.036)
highSE -0.002 0.005 0.017 -0.002 0.007 0.034
(0.024) (0.027) (0.024) (0.039) (0.028) (0.039)
medSE 0.044 0.042 0.007 0.033 0.050 0.092 ^
(0.030) (0.033) (0.029) (0.048) (0.034) (0.047)
Agglomeration 0.019 *** -0.003 0.007 0.028 ** 0.006 0.021 **
(0.005) (0.005) (0.005) (0.009) (0.007) (0.008)
lag.U -0.070 * -0.084 ** -0.036 0.095 -0.015 0.005
(0.031) (0.032) (0.033) (0.059) (0.041) (0.029)
lag.V 0.069 * 0.086 ** 0.035 -0.095 0.015 -0.006
(0.032) (0.033) (0.034) (0.059) (0.042) (0.029)
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
logLik 299.984 276.552 276.644 193.812 247.251 232.410
AIC -577.969 -531.104 -531.288 -365.623 -472.503 -442.819
BIC -545.149 -498.825 -499.412 -335.053 -441.303 -410.228
N. obs. 146 139 134 119 126 143
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
*** p < 0.001; ** p < 0.01; * p < 0.05; ^ p < 0.1.
Column names: names, All Professions, Machine & Vehicle Technology, Mechatronics, Energy, Electrical, Medical Health, Business Management, Sales
# Export to HTML
quick_html(ht, file = "./Outputs/Regressions/Profession_differences.html")
kf.service.services: KApplicationTrader: mimeType "x-scheme-handler/file" not found
kf.service.services: KApplicationTrader: mimeType "x-scheme-handler/file" not found
library(ggplot2)
library(dplyr)
library(tidyr)
Attaching package: ‘tidyr’
The following objects are masked from ‘package:Matrix’:
expand, pack, unpack
library(stringr)
library(ggplot2)
# Extract coefficients and create a data frame
# Extract coefficients and create a data frame
# Extract coefficients, standard errors and create a data frame
coef_df <- do.call(rbind, lapply(names(model_list), function(profession) {
model <- model_list[[profession]]
tidy_model <- broom::tidy(model)
tidy_model$Profession <- profession
tidy_model
}))
Opening in existing browser session.
# Function to add line breaks to labels
add_line_breaks <- function(label, width = 30) {
str_wrap(label, width = width)
}
#Extract coefficients, standard errors and create a data frame
coef_df <- do.call(rbind, lapply(names(model_list), function(profession) {
model <- model_list[[profession]]
tidy_model <- broom::tidy(model)
tidy_model$Profession <- profession
tidy_model
}))
# Create an offset variable for the y-axis
coef_df <- coef_df %>%
group_by(term) %>%
mutate(offset = as.numeric(factor(Profession)) * 0.1) %>% # Adjust the offset multiplier as needed
ungroup()
# Add the English profession column
coef_df$term[coef_df$term=="(Intercept)"] <- "Efficiency"
coef_df$term[coef_df$term=="AgglomerationDistPop"] <- "Agglomeration"
coef_df$term[coef_df$term=="lag.U"] <- "U.lag"
coef_df$term[coef_df$term=="lag.V"] <- "V.lag"
coef_df1 <- coef_df[coef_df$term %in% c("U","V","U.lag","V.lag","Efficiency", "lambda"),]
coef_df2 <- coef_df[!(coef_df$term %in% c("U","V","U.lag","V.lag","Efficiency","lambda")),]
library(viridis)
Loading required package: viridisLite
library(scales)
Attaching package: ‘scales’
The following object is masked from ‘package:viridis’:
viridis_pal
The following object is masked from ‘package:huxtable’:
number_format
dark_viridis_colors <- viridis_pal(option = "G")(10)[3:8]
# Plot the coefficients with error bars and vertical offset
coef_df1$term <- factor(coef_df1$term, levels = c("lambda", "U.lag","V.lag", "U", "V", "Efficiency" ))
plot_eff1 <- ggplot(coef_df1, aes(x = term, y = estimate, color = Profession))+
geom_point(position = position_dodge(width = 0.8), size = 3) +
geom_errorbar(aes(ymin = estimate - 1.96 * std.error, ymax = estimate + 1.96 *std.error),
width = 0.2, size = 1, position = position_dodge(width = 0.8))+
geom_vline(xintercept = 0, linetype = "solid", color = "black", size = 6) +
coord_flip() +
theme_minimal() +
labs(
x = "Coefficient Term",
y = "Estimate",
color = "Profession") +
theme(axis.text.x = element_text(size = 16),
axis.text.y = element_text(size = 16),
legend.position = "bottom", legend.text = element_text(size = 14),
plot.margin = margin(t = 10, r = 40, b = 10, l = 10),
legend.title = element_text(size = 16),
legend.title.position = "top",
legend.box = "horizontal",
# Adjust margins (top, right, bottom, left)
panel.grid.major = element_line(color = "darkgray", size = 0.25), # Darker major grid lines
panel.grid.minor = element_line(color = "gray", size = 0.25),
axis.title = element_text(size = 16),
plot.title = element_text(size = 20)) +
guides(color = guide_legend(title.position = "top", nrow = 6, byrow = TRUE)) +
# scale_y_continuous(expand = expansion(mult = c(0.1, 0.1)),limits = c(-0.2, 0.2)) +
scale_x_discrete(labels = function(x) sapply(x, add_line_breaks))+
scale_color_manual(values=custom_disc_color) + guides(color = guide_legend(ncol = 2))
Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
Please use `linewidth` instead.Warning: The `size` argument of `element_line()` is deprecated as of ggplot2 3.4.0.
Please use the `linewidth` argument instead.
plot_eff2 <- ggplot(coef_df2, aes(color = Profession, y = estimate, x= term)) +
geom_point(position = position_dodge(width = 0.8), size = 3) +
geom_errorbar(aes(ymin = estimate - 1.96 *std.error, ymax = estimate + 1.96 *std.error),
width = 0.2, size = 1, position = position_dodge(width = 0.8)) +
geom_vline(xintercept = 0, linetype = "solid", color = "black", size = 1.2)+
coord_flip() +
theme_minimal() +
labs(
x = "Coefficient Term",
y = "Estimate",
color = "Profession") +
theme(axis.text.x = element_text(size = 16),
axis.text.y = element_text(size = 16),
axis.title = element_text(size = 16),
# Adjust margins (top, right, bottom, left)
panel.grid.major = element_line(color = "darkgray", size = 0.25), # Darker major grid lines
panel.grid.minor = element_line(color = "gray", size = 0.25),
plot.title = element_text(size = 20),
legend.position = "bottom", legend.text = element_text(size = 14),
plot.margin = margin(t = 10, r = 40, b = 10, l = 10),
legend.title = element_text(size = 16)) +
guides(color = guide_legend(title.position = "top", nrow = 6, byrow = TRUE)) +
scale_y_continuous(expand = expansion(mult = c(0.15, 0.15)),limits = c(-0.21, 0.21)) +
scale_x_discrete(labels = function(x) sapply(x, add_line_breaks))+
scale_color_manual(values=custom_disc_color)
plot_eff1

library(ggplot2)
library(ggpubr)
Attaching package: ‘ggpubr’
The following object is masked from ‘package:huxtable’:
font
# Arrange with shared legend
combined <- ggarrange(
plot_eff1, plot_eff2,
ncol = 2, nrow = 1,
common.legend = TRUE, # <- share legend
legend = "bottom" # <- put legend below
)
# Save as PNG
ggsave("./Outputs/Figures/plots_combined.png", combined,
width = 12, height = 12, units = "in", dpi = 600)

LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQogCgoKYGBge3IgZmlnLmhlaWdodD0xMiwgZmlnLndpZHRoPTE2fQoKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KHNmKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KHNwYXRpYWxyZWcpCmxpYnJhcnkoc3BkZXApCgpybShsaXN0PWxzKCkpCm15cGF0aCA8LSAiLi9EYXRhQmFja3Vwcy8iCnByb2Zlc3Npb25fbmFtZXMgPC0gYygKICAic2FsZXMgcHJvZmVzc2lvbnMiLAogICJtZWNoYXRyb25pY3MsIGVuZXJneSwgYW5kIGVsZWN0cmljYWwgcHJvZmVzc2lvbnMiLAogICJwcm9mZXNzaW9ucyBpbiBidXNpbmVzcyBtYW5hZ2VtZW50IGFuZCBvcmdhbml6YXRpb24iLAogICJtZWRpY2FsIGhlYWx0aCBwcm9mZXNzaW9ucyIsCiAgIm1hY2hpbmUgYW5kIHZlaGljbGUgdGVjaG5vbG9neSBwcm9mZXNzaW9ucyIsCiAgImFsbCBwcm9mZXNzaW9ucyIKKQoKa3JlaXNlIDwtIHNmOjpzdF9yZWFkKCIuL0RhdGFQcmVwYXJhdGlvbi9TaGFwZXMvS3JlaXNlL3ZnMTAwMF8xMi0zMS51dG0zMnMuc2hhcGUuZWJlbmVuL3ZnMTAwMF9lYmVuZW5fMTIzMS9WRzEwMDBfS1JTLnNocCIpICMgdGhvdWdoIG5vdCBpbXBvcnRlZCBkaXJlY3RseSwgYWxsIG90aGVyIGF1eGlsaWFyeSBmaWxlcyBtdXN0IGJlIHByZXNlbnQgaW4gdGhlIHBhdGgKa3JlaXNlIDwtIHN0X3RyYW5zZm9ybShrcmVpc2UsICJXR1M4NCIpCmtyZWlzZV9tZXJnZWQgPC0ga3JlaXNlICU+JQogIGdyb3VwX2J5KFNOX0wpICU+JQogIHN1bW1hcml6ZShnZW9tZXRyeSA9IHN0X3VuaW9uKGdlb21ldHJ5KSkKYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTEyLCBmaWcud2lkdGg9MTZ9CmxpYnJhcnkoc3RyaW5ncikKbGlicmFyeShnZ3JlcGVsKQoKCm1vZGVsX2xpc3QgPC0gbGlzdCgpCgpncmFwaGljc19saXN0IDwtIGxpc3QoKQpzcGF0aWFsX2NsdXN0ZXJpbmdfbGlzdCA8LSBsaXN0KCkKbG9hZChmaWxlID0gIi4vRGF0YUJhY2t1cHMvd2VpZ2h0c19kYXRhLlJEYXRhIikKCmZvciAocCBpbiBwcm9mZXNzaW9uX25hbWVzKQp7CiNwIDwtIHByb2Zlc3Npb25fbmFtZXNbMV0gIAogIApsb2FkKHBhc3RlMChteXBhdGgscCwiTS5SZGF0YSIpKQpsb2FkKGZpbGUgPSAiLi9EYXRhQmFja3Vwcy93ZWlnaHRzX2RhdGEuUkRhdGEiKQoKcHJpbnQocCkKCnRhcmdldCA9ICJNIgpmb3JtdWxhX2Jhc2UgPC0gYXMuZm9ybXVsYShwYXN0ZTAodGFyZ2V0LCIgIH4gVSArIFYgIikpCmZvcm11bGEgPC0gYXMuZm9ybXVsYShwYXN0ZTAodGFyZ2V0LCIgICB+IFUgKyBWICsgdW5lbXAyNSArIGNvbnMgKyBoaWdoU0UgKyAgbWVkU0UgICIpKQpmb3JtdWxhX3B1Yl9udW0gPC0gYXMuZm9ybXVsYShwYXN0ZTAodGFyZ2V0LCIgICB+IFUgKyBWICsgdW5lbXAyNSArIGNvbnMgKyBoaWdoU0UgKyBtZWRTRSAgKyBBZ2dsb21lcmF0aW9uIikpCnRhcmdldCA9ICJNIgoKCgpwcm9mZXNzaW9uX25ldyRBZ2dsb21lcmF0aW9uIDwtIHByb2Zlc3Npb25fbmV3JEFnZ2xvbWVyYXRpb25QdWJsaWNQb3A0OQoKCiMgQmVnaW4gV2VpZ2h0IE1hdHJpeCBjb21wdXRhdGlvbgpjb2x1bW5zX29mX2ludGVyZXN0IDwtIGMoJ00nLCdVJywgJ1YnLCAndW5lbXAyNScsICdjb25zJywgJ2xvd1NFJywgJ21lZFNFJywgJ0FnZ2xvbWVyYXRpb24nKQojIFJlcGxhY2UgSW5mIGFuZCAtSW5mIHdpdGggTkEgaW4gdGhlIHNwZWNpZmllZCBjb2x1bW5zCnByb2Zlc3Npb25fbmV3W2NvbHVtbnNfb2ZfaW50ZXJlc3RdIDwtIGxhcHBseShwcm9mZXNzaW9uX25ld1tjb2x1bW5zX29mX2ludGVyZXN0XSwgZnVuY3Rpb24oeCkgcmVwbGFjZSh4LCBpcy5pbmZpbml0ZSh4KSwgTkEpKQojIFJlbW92ZSByb3dzIHdpdGggYW55IE5BIHZhbHVlcyBpbiB0aGUgc3BlY2lmaWVkIGNvbHVtbnMKcHJvZmVzc2lvbl9uZXcgPC0gcHJvZmVzc2lvbl9uZXdbY29tcGxldGUuY2FzZXMocHJvZmVzc2lvbl9uZXdbY29sdW1uc19vZl9pbnRlcmVzdF0pLCBdCgpiZXN0X1dlaWdodHNfcHVibGljX3BvcCA8LSBiZXN0X1dlaWdodHNfcHVibGljX3BvcF9tYXRbY29sbmFtZXMoYmVzdF9XZWlnaHRzX3B1YmxpY19wb3BfbWF0KSAlaW4lIHByb2Zlc3Npb25fbmV3JHJlZ2lvbixjb2xuYW1lcyhiZXN0X1dlaWdodHNfcHVibGljX3BvcF9tYXQpICVpbiUgcHJvZmVzc2lvbl9uZXckcmVnaW9uXQoKIyMjIyMjIyMjIyMjIyMjIwpsaWJyYXJ5KGRwbHlyKQoKZGlzdGFuY2VzX3JlbGV2YW50X3BvcCA8LSBtZXJnZShkaXN0YW5jZXNfcmVsZXZhbnQsZmluYWwsIGJ5Lng9ImNpdHkuLi4xIixieS55PSJjaXR5IikKZGlzdGFuY2VzX3JlbGV2YW50X3BvcCA8LSBtZXJnZShkaXN0YW5jZXNfcmVsZXZhbnRfcG9wLGZpbmFsLGJ5Lng9ImNpdHkuLi40IixieS55PSJjaXR5IikKCnByb2Zlc3Npb25fbmV3IDwtIHByb2Zlc3Npb25fbmV3WyFpcy5uYShwcm9mZXNzaW9uX25ldyRPcGVuUG9zaXRpb25zKSxdCgojIyBBcyBhbGwgUHJvZmVzc2lvbnMgaGF2ZSBkaWZmZXJlbnQgUmVnaW9ucywgd2UgbmVlZCB0byBSZWR1Y2UgdGhlIG1hdHJpeCB0byByZWxldmFudCByZWdpb25zLiBBcyB0aGUgaW5pdGlhbCBtYXRyaXgsIGFscmVhZHkgZG9lcyBub3QgY29udGFpbiBhbGwgcmVnaW9ucywgaXQgaXMgZWFzaWVyIHRvIHJlLWNhbGN1bGF0ZSBldnJ5dGhpbmcuCmRpc3RhbmNlc19yZWxldmFudF90ZXN0X3B1YmxpYyA8LSAgZGlzdGFuY2VzX3JlbGV2YW50X3BvcCAlPiUgZ3JvdXBfYnkoQUJEaXN0cmljdC4uLjYpICU+JSBtdXRhdGUoZGlzdHJpY3RfcG9wID0gc3VtKHVuaXF1ZShtYXhQb3B1bGF0aW9uLnkpKSkgJT4lIHVuZ3JvdXAgJT4lIGZpbHRlcihBQkRpc3RyaWN0Li4uMyAhPSBBQkRpc3RyaWN0Li4uNikgICU+JSAgZmlsdGVyKHB1YmxpYyA8PSA1MS4yODE2NykgJT4lIGdyb3VwX2J5KGNpdHkuLi4xLCBBQkRpc3RyaWN0Li4uMywgQUJEaXN0cmljdC4uLjYpICU+JSAgc3VtbWFyaXNlKGRpc3RyaWN0X3BvcCA9IG1heChkaXN0cmljdF9wb3ApLCBjb3VudD0gc3VtKHVuaXF1ZShtYXhQb3B1bGF0aW9uLnkpKSwgV2VpZ2h0PWNvdW50L2Rpc3RyaWN0X3BvcCwgLmdyb3Vwcz0ia2VlcCIpICU+JSBncm91cF9ieShBQkRpc3RyaWN0Li4uMywgQUJEaXN0cmljdC4uLjYpICU+JSBzdW1tYXJpc2UoV2VpZ2h0PW1lYW4oV2VpZ2h0KSwgLmdyb3Vwcz0ia2VlcCIpCgoKV2VpZ2h0c19wdWJsaWNfcG9wICA8LSBtYXRyaXgoMCwgbnJvdz1ucm93KHByb2Zlc3Npb25fbmV3KSwgbmNvbD1ucm93KHByb2Zlc3Npb25fbmV3KSkKICByb3cubmFtZXMoV2VpZ2h0c19wdWJsaWNfcG9wKTwtIHByb2Zlc3Npb25fbmV3JHJlZ2lvbgogIGNvbG5hbWVzKFdlaWdodHNfcHVibGljX3BvcCkgPC0gcHJvZmVzc2lvbl9uZXckcmVnaW9uCgogIGZvcihpIGluIDE6bnJvdyhkaXN0YW5jZXNfcmVsZXZhbnRfdGVzdF9wdWJsaWMpKQogIHsKICAgIFdlaWdodHNfcHVibGljX3BvcFtyb3cubmFtZXMoV2VpZ2h0c19wdWJsaWNfcG9wKT09ZGlzdGFuY2VzX3JlbGV2YW50X3Rlc3RfcHVibGljJEFCRGlzdHJpY3QuLi4zW2ldLCBjb2xuYW1lcyhXZWlnaHRzX3B1YmxpY19wb3ApPT1kaXN0YW5jZXNfcmVsZXZhbnRfdGVzdF9wdWJsaWMkQUJEaXN0cmljdC4uLjZbaV1dPC0gZGlzdGFuY2VzX3JlbGV2YW50X3Rlc3RfcHVibGljJFdlaWdodFtpXQogIH0KICAKICBXZWlnaHRzX3B1YmxpY19wb3AgPC0gV2VpZ2h0c19wdWJsaWNfcG9wL21heChXZWlnaHRzX3B1YmxpY19wb3ApCgogIG1vZGVsIDwtIGxtU0xYKGZvcm11bGFfcHViX251bSAsIHByb2Zlc3Npb25fbmV3LCBtYXQybGlzdHcoV2VpZ2h0c19wdWJsaWNfcG9wLCBzdHlsZT0iTSIpLCBuYS5hY3Rpb249bmEub21pdCwgemVyby5wb2xpY3k9VFJVRSwgRHVyYmluPX4gIFUgKyBWICAtMSkKCiAgbW9kZWxfbGlzdCR4IDwtIG1vZGVsCiAgbmFtZXMobW9kZWxfbGlzdCk8LWMobmFtZXMobW9kZWxfbGlzdClbMToobGVuZ3RoKG5hbWVzKG1vZGVsX2xpc3QpKSktMV0sIHApCiAgCiAgIwogIGVzdGltYXRlX3ZlY3RvcjwtIG1vZGVsJGNvZWZmaWNpZW50c1stYygyLDMsOToxMCldCiAgZXN0aW1hdGVfdmFsdWVzIDwtIGFzLm1hdHJpeChjYmluZCgiKEludGVyY2VwdCkiPTEsc3RfZHJvcF9nZW9tZXRyeShwcm9mZXNzaW9uX25ld1ssbmFtZXMoZXN0aW1hdGVfdmVjdG9yWy1jKDEpXSldKSkpCiAgCiAgCiAgcHJvZmVzc2lvbl9uZXckRWZmaWNpZW5jeSA8LSBleHAoZXN0aW1hdGVfdmFsdWVzICUqJSBlc3RpbWF0ZV92ZWN0b3IpIAoKbWFwX2VmZmljaWVuY3kgPC0gZ2dwbG90KCkgKyAKICBnZW9tX3NmKGRhdGE9ZGlzdHJpY3RzLCBmaWxsID0gIiNlNGU0ZTQiKSArCiAgZ2VvbV9zZihkYXRhPXN0X2FzX3NmKHByb2Zlc3Npb25fbmV3KSwgYWVzKGZpbGwgPSBFZmZpY2llbmN5KSkrCiAgZ2VvbV9zZihkYXRhPWtyZWlzZV9tZXJnZWQsZmlsbD1OQSwKICAgICAgICAgIGNvbG9yID0gIiNlYzcwNjMiLCAgIAogICAgICAgICAgbHdkID0gMS4yKSArCiAgdGhlbWUobGVnZW5kLnRleHQuYWxpZ24gPSAxKSAgKwogIGxhYnMoZmlsbCA9IHN0cl93cmFwKHBhc3RlMCgiRWZmaWNpZW5jeSBmb3IgIiwgcCksIHdpZHRoID0gNTApKSArIAogIGd1aWRlcygKICAgIGZpbGwgPSBndWlkZV9jb2xvcmJhcihkaXJlY3Rpb24gPSAiaG9yaXpvbnRhbCIsIHRpdGxlLmhqdXN0PTAuNSwgdGl0bGUucG9zaXRpb249InRvcCIsIGJhcndpZHRoID0gMjAsICAjIEFkanVzdCB0aGlzIHZhbHVlIHRvIGNoYW5nZSB0aGUgd2lkdGggb2YgdGhlIGNvbG9yYmFyCiAgICAgIGJhcmhlaWdodCA9IDEgICksIAojIEFkanVzdCByb3dzIGZvciB0aGUgZmlsbCBsZWdlbmQKICApICsKICB0aGVtZSgKICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLAogICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE4KSwKICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTgsIGZhY2U9ImJvbGQiKSwKICAgIGxlZ2VuZC5ib3ggPSAiaG9yaXpvbnRhbCIsCiAgICBsZWdlbmQuYm94Lmp1c3QgPSAiY2VudGVyIiwKICAgIGxlZ2VuZC5zcGFjaW5nLnggPSB1bml0KDAuNSwgImNtIikgCiAgKQoKCm1hcF9lZmZpY2llbmN5IDwtIG1hcF9lZmZpY2llbmN5ICsgIHNjYWxlX2ZpbGxfZ3JhZGllbnRuKGNvbG9ycyA9IGN1c3RvbV9jb2xvcnMoMTAwKSwgbmEudmFsdWU9IiNlNGU0ZTQiKQpwcmludChtYXBfZWZmaWNpZW5jeSkKCgogIGdyYXBoaWNzX2xpc3QkeCA8LSBtYXBfZWZmaWNpZW5jeQogIG5hbWVzKGdyYXBoaWNzX2xpc3QpPC1uYW1lcyhtb2RlbF9saXN0KQoKfQoKYGBgCgoKCmBgYHtyIGZpZy5oZWlnaHQ9MjQsIGZpZy53aWR0aD0xNn0KCmxpYnJhcnkoZ3JpZEV4dHJhKQpjb21iaW5lZF9wbG90IDwtIGRvLmNhbGwoZ3JpZC5hcnJhbmdlLCBjKGdyYXBoaWNzX2xpc3QsIG5jb2wgPSAyLCBucm93ID0gMykpCnByaW50KGNvbWJpbmVkX3Bsb3QpCgoKI2NvbWJpbmVkX3Bsb3QgPC0gZG8uY2FsbChncmlkLmFycmFuZ2UsIGMoc3BhdGlhbF9jbHVzdGVyaW5nX2xpc3QsIG5jb2wgPSAyLCBucm93ID0gMykpCiNwcmludChjb21iaW5lZF9wbG90KQoKCmBgYAoKYGBge3J9CmxpYnJhcnkoanRvb2xzKQpsaWJyYXJ5KGh1eHRhYmxlKQojIENvbWJpbmUgbW9kZWwgc3VtbWFyaWVzIGludG8gYSBzaW5nbGUgaHV4dGFibGUKaHQgPC0gZXhwb3J0X3N1bW1zKG1vZGVsX2xpc3QkYGFsbCBwcm9mZXNzaW9uc2AsCiAgICAgICAgICAgICAgICAgICBtb2RlbF9saXN0JGBtYWNoaW5lIGFuZCB2ZWhpY2xlIHRlY2hub2xvZ3kgcHJvZmVzc2lvbnNgLAogICAgICAgICAgICAgICAgICAgbW9kZWxfbGlzdCRgbWVjaGF0cm9uaWNzLCBlbmVyZ3ksIGFuZCBlbGVjdHJpY2FsIHByb2Zlc3Npb25zYCwKICAgICAgICAgICAgICAgICAgIG1vZGVsX2xpc3QkYG1lZGljYWwgaGVhbHRoIHByb2Zlc3Npb25zYCwKICAgICAgICAgICAgICAgICAgIG1vZGVsX2xpc3QkYHByb2Zlc3Npb25zIGluIGJ1c2luZXNzIG1hbmFnZW1lbnQgYW5kIG9yZ2FuaXphdGlvbmAsCiAgICAgICAgICAgICAgICAgICBtb2RlbF9saXN0JGBzYWxlcyBwcm9mZXNzaW9uc2AsCiAgICAgICAgICAgICAgICAgICBtb2RlbC5uYW1lcyA9IGMoIkFsbCBQcm9mZXNzaW9ucyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk1hY2hpbmUgJiBWZWhpY2xlIFRlY2hub2xvZ3kiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJNZWNoYXRyb25pY3MsIEVuZXJneSwgRWxlY3RyaWNhbCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk1lZGljYWwgSGVhbHRoIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQnVzaW5lc3MgTWFuYWdlbWVudCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNhbGVzIiksIAogIG51bWJlcl9mb3JtYXQgPSAiJS4zZiIsIAogIHN0YXRpc3RpY3MgPSBjKCJsb2dMaWsiLCJBSUMiLCJCSUMiLCJOLiBvYnMuIiA9ICJub2JzIiksCiAgc3RhcnMgPSBjKGAqKipgID0gMC4wMDEsIGAqKmAgPSAwLjAxLCBgKmAgPSAwLjA1LCBgXmAgPSAwLjEpKQoKIyBBcHBseSBhbnkgYWRkaXRpb25hbCBmb3JtYXR0aW5nIHRvIHRoZSBodXh0YWJsZSBpZiBuZWVkZWQKaHQgPC0gaHQgJT4lCiAgCiAgc2V0X2hlYWRlcl9yb3dzKDEsIFRSVUUpICU+JQogIHNldF9oZWFkZXJfY29scygxLCBUUlVFKQoKIyBEaXNwbGF5IHRoZSBodXh0YWJsZQpwcmludF9zY3JlZW4oaHQpCgojIEV4cG9ydCB0byBIVE1MCnF1aWNrX2h0bWwoaHQsIGZpbGUgPSAiLi9PdXRwdXRzL1JlZ3Jlc3Npb25zL1Byb2Zlc3Npb25fZGlmZmVyZW5jZXMuaHRtbCIpCgoKCmBgYAoKCgpgYGB7UiBmaWcuaGVpZ2h0PTEwLCBmaWcud2lkdGg9N30KCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShkcGx5cikKbGlicmFyeSh0aWR5cikKbGlicmFyeShzdHJpbmdyKQpsaWJyYXJ5KGdncGxvdDIpCgoKCiMgRXh0cmFjdCBjb2VmZmljaWVudHMgYW5kIGNyZWF0ZSBhIGRhdGEgZnJhbWUKIyBFeHRyYWN0IGNvZWZmaWNpZW50cyBhbmQgY3JlYXRlIGEgZGF0YSBmcmFtZQojIEV4dHJhY3QgY29lZmZpY2llbnRzLCBzdGFuZGFyZCBlcnJvcnMgYW5kIGNyZWF0ZSBhIGRhdGEgZnJhbWUKY29lZl9kZiA8LSBkby5jYWxsKHJiaW5kLCBsYXBwbHkobmFtZXMobW9kZWxfbGlzdCksIGZ1bmN0aW9uKHByb2Zlc3Npb24pIHsKICBtb2RlbCA8LSBtb2RlbF9saXN0W1twcm9mZXNzaW9uXV0KICB0aWR5X21vZGVsIDwtIGJyb29tOjp0aWR5KG1vZGVsKQogIHRpZHlfbW9kZWwkUHJvZmVzc2lvbiA8LSBwcm9mZXNzaW9uCiAgdGlkeV9tb2RlbAp9KSkKCgojIEZ1bmN0aW9uIHRvIGFkZCBsaW5lIGJyZWFrcyB0byBsYWJlbHMKYWRkX2xpbmVfYnJlYWtzIDwtIGZ1bmN0aW9uKGxhYmVsLCB3aWR0aCA9IDMwKSB7CiAgc3RyX3dyYXAobGFiZWwsIHdpZHRoID0gd2lkdGgpCn0KCgoKICNFeHRyYWN0IGNvZWZmaWNpZW50cywgc3RhbmRhcmQgZXJyb3JzIGFuZCBjcmVhdGUgYSBkYXRhIGZyYW1lCmNvZWZfZGYgPC0gZG8uY2FsbChyYmluZCwgbGFwcGx5KG5hbWVzKG1vZGVsX2xpc3QpLCBmdW5jdGlvbihwcm9mZXNzaW9uKSB7CiAgbW9kZWwgPC0gbW9kZWxfbGlzdFtbcHJvZmVzc2lvbl1dCiAgdGlkeV9tb2RlbCA8LSBicm9vbTo6dGlkeShtb2RlbCkKICB0aWR5X21vZGVsJFByb2Zlc3Npb24gPC0gcHJvZmVzc2lvbgogIHRpZHlfbW9kZWwKfSkpCgojIENyZWF0ZSBhbiBvZmZzZXQgdmFyaWFibGUgZm9yIHRoZSB5LWF4aXMKY29lZl9kZiA8LSBjb2VmX2RmICU+JQogIGdyb3VwX2J5KHRlcm0pICU+JQogIG11dGF0ZShvZmZzZXQgPSBhcy5udW1lcmljKGZhY3RvcihQcm9mZXNzaW9uKSkgKiAwLjEpICU+JSAgIyBBZGp1c3QgdGhlIG9mZnNldCBtdWx0aXBsaWVyIGFzIG5lZWRlZAogIHVuZ3JvdXAoKQoKIyBBZGQgdGhlIEVuZ2xpc2ggcHJvZmVzc2lvbiBjb2x1bW4KCgoKY29lZl9kZiR0ZXJtW2NvZWZfZGYkdGVybT09IihJbnRlcmNlcHQpIl0gPC0gIkVmZmljaWVuY3kiCmNvZWZfZGYkdGVybVtjb2VmX2RmJHRlcm09PSJBZ2dsb21lcmF0aW9uRGlzdFBvcCJdIDwtICJBZ2dsb21lcmF0aW9uIgoKY29lZl9kZiR0ZXJtW2NvZWZfZGYkdGVybT09ImxhZy5VIl0gPC0gIlUubGFnIgpjb2VmX2RmJHRlcm1bY29lZl9kZiR0ZXJtPT0ibGFnLlYiXSA8LSAiVi5sYWciCgoKY29lZl9kZjEgPC0gY29lZl9kZltjb2VmX2RmJHRlcm0gJWluJSBjKCJVIiwiViIsIlUubGFnIiwiVi5sYWciLCJFZmZpY2llbmN5IiwgImxhbWJkYSIpLF0KCmNvZWZfZGYyIDwtIGNvZWZfZGZbIShjb2VmX2RmJHRlcm0gJWluJSBjKCJVIiwiViIsIlUubGFnIiwiVi5sYWciLCJFZmZpY2llbmN5IiwibGFtYmRhIikpLF0KCmxpYnJhcnkodmlyaWRpcykKbGlicmFyeShzY2FsZXMpCmRhcmtfdmlyaWRpc19jb2xvcnMgPC0gdmlyaWRpc19wYWwob3B0aW9uID0gIkciKSgxMClbMzo4XQoKIyBQbG90IHRoZSBjb2VmZmljaWVudHMgd2l0aCBlcnJvciBiYXJzIGFuZCB2ZXJ0aWNhbCBvZmZzZXQKCmNvZWZfZGYxJHRlcm0gPC0gZmFjdG9yKGNvZWZfZGYxJHRlcm0sIGxldmVscyA9IGMoImxhbWJkYSIsICJVLmxhZyIsIlYubGFnIiwgIlUiLCAiViIsICAiRWZmaWNpZW5jeSIgKSkKCnBsb3RfZWZmMSA8LSBnZ3Bsb3QoY29lZl9kZjEsIGFlcyh4ID0gdGVybSwgeSA9IGVzdGltYXRlLCBjb2xvciA9IFByb2Zlc3Npb24pKSsKICBnZW9tX3BvaW50KHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjgpLCBzaXplID0gMykgKwogIGdlb21fZXJyb3JiYXIoYWVzKHltaW4gPSBlc3RpbWF0ZSAtIDEuOTYgKiBzdGQuZXJyb3IsIHltYXggPSBlc3RpbWF0ZSArICAxLjk2ICpzdGQuZXJyb3IpLAogICAgICAgICAgICAgICAgd2lkdGggPSAwLjIsIHNpemUgPSAxLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC44KSkrCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAic29saWQiLCBjb2xvciA9ICJibGFjayIsIHNpemUgPSA2KSArCiAgY29vcmRfZmxpcCgpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIGxhYnMoCiAgICAgICB4ID0gIkNvZWZmaWNpZW50IFRlcm0iLAogICAgICAgeSA9ICJFc3RpbWF0ZSIsCiAgICAgICBjb2xvciA9ICJQcm9mZXNzaW9uIikgKwp0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYpLAogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNiksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0KSwKICAgICAgICBwbG90Lm1hcmdpbiA9IG1hcmdpbih0ID0gMTAsIHIgPSA0MCwgYiA9IDEwLCBsID0gMTApLAogIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYpLAogIGxlZ2VuZC50aXRsZS5wb3NpdGlvbiA9ICJ0b3AiLAogIGxlZ2VuZC5ib3ggPSAiaG9yaXpvbnRhbCIsCiAgICAjIEFkanVzdCBtYXJnaW5zICh0b3AsIHJpZ2h0LCBib3R0b20sIGxlZnQpCiAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9saW5lKGNvbG9yID0gImRhcmtncmF5Iiwgc2l6ZSA9IDAuMjUpLCAgIyBEYXJrZXIgbWFqb3IgZ3JpZCBsaW5lcwogICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfbGluZShjb2xvciA9ICJncmF5Iiwgc2l6ZSA9IDAuMjUpLAogICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNiksCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAyMCkpICsKICBndWlkZXMoY29sb3IgPSBndWlkZV9sZWdlbmQodGl0bGUucG9zaXRpb24gPSAidG9wIiwgbnJvdyA9IDYsIGJ5cm93ID0gVFJVRSkpICsKIyAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGV4cGFuc2lvbihtdWx0ID0gYygwLjEsIDAuMSkpLGxpbWl0cyA9IGMoLTAuMiwgMC4yKSkgICArCiAgc2NhbGVfeF9kaXNjcmV0ZShsYWJlbHMgPSBmdW5jdGlvbih4KSBzYXBwbHkoeCwgYWRkX2xpbmVfYnJlYWtzKSkrCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jdXN0b21fZGlzY19jb2xvcikgKyBndWlkZXMoY29sb3IgPSBndWlkZV9sZWdlbmQobmNvbCA9IDIpKQoKCgpwbG90X2VmZjIgPC0gZ2dwbG90KGNvZWZfZGYyLCBhZXMoY29sb3IgPSBQcm9mZXNzaW9uLCB5ID0gZXN0aW1hdGUsIHg9IHRlcm0pKSArCiAgZ2VvbV9wb2ludChwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC44KSwgc2l6ZSA9IDMpICArCiAgZ2VvbV9lcnJvcmJhcihhZXMoeW1pbiA9IGVzdGltYXRlIC0gIDEuOTYgKnN0ZC5lcnJvciwgeW1heCA9IGVzdGltYXRlICsgIDEuOTYgKnN0ZC5lcnJvciksCiAgICAgICAgICAgICAgICB3aWR0aCA9IDAuMiwgc2l6ZSA9IDEsIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjgpKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAic29saWQiLCBjb2xvciA9ICJibGFjayIsIHNpemUgPSAxLjIpKwogIGNvb3JkX2ZsaXAoKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICBsYWJzKAogICAgICAgeCA9ICJDb2VmZmljaWVudCBUZXJtIiwKICAgICAgIHkgPSAiRXN0aW1hdGUiLAogICAgICAgY29sb3IgPSAiUHJvZmVzc2lvbiIpICsKdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2KSwKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYpLAogICAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYpLAogICAgICAgICMgQWRqdXN0IG1hcmdpbnMgKHRvcCwgcmlnaHQsIGJvdHRvbSwgbGVmdCkKICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2xpbmUoY29sb3IgPSAiZGFya2dyYXkiLCBzaXplID0gMC4yNSksICAjIERhcmtlciBtYWpvciBncmlkIGxpbmVzCiAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9saW5lKGNvbG9yID0gImdyYXkiLCBzaXplID0gMC4yNSksCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAyMCksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0KSwKICAgICAgcGxvdC5tYXJnaW4gPSBtYXJnaW4odCA9IDEwLCByID0gNDAsIGIgPSAxMCwgbCA9IDEwKSwKICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2KSkgKwogIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZCh0aXRsZS5wb3NpdGlvbiA9ICJ0b3AiLCBucm93ID0gNiwgYnlyb3cgPSBUUlVFKSkgKwogIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBleHBhbnNpb24obXVsdCA9IGMoMC4xNSwgMC4xNSkpLGxpbWl0cyA9IGMoLTAuMjEsIDAuMjEpKSAgICsKICBzY2FsZV94X2Rpc2NyZXRlKGxhYmVscyA9IGZ1bmN0aW9uKHgpIHNhcHBseSh4LCBhZGRfbGluZV9icmVha3MpKSsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWN1c3RvbV9kaXNjX2NvbG9yKQoKcGxvdF9lZmYxCmBgYAoKCgoKYGBge3J9CmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShnZ3B1YnIpCgoKIyBBcnJhbmdlIHdpdGggc2hhcmVkIGxlZ2VuZApjb21iaW5lZCA8LSBnZ2FycmFuZ2UoCiAgcGxvdF9lZmYxLCBwbG90X2VmZjIsCiAgbmNvbCA9IDIsIG5yb3cgPSAxLAogIGNvbW1vbi5sZWdlbmQgPSBUUlVFLCAgICMgPC0gc2hhcmUgbGVnZW5kCiAgbGVnZW5kID0gImJvdHRvbSIgICAgICAgIyA8LSBwdXQgbGVnZW5kIGJlbG93CikKCiMgU2F2ZSBhcyBQTkcKZ2dzYXZlKCIuL091dHB1dHMvRmlndXJlcy9wbG90c19jb21iaW5lZC5wbmciLCBjb21iaW5lZCwKICAgICAgIHdpZHRoID0gMTIsIGhlaWdodCA9IDEyLCB1bml0cyA9ICJpbiIsIGRwaSA9IDYwMCkKYGBgCgo=